#!/user/bin/python3
# @Author:  LSY
# @Date:    2020/9/14
from app.database import convert
from app.models.bo.gaolu.gaolu_reason_status_bo import GaoLuReasonStatusBO
from app.models.bo.hanfan.hanfan_fuel_tracking_bo import HanFanFuelTrackingBO
from app.models.bo.hanfan.hanfan_input_param_bo import HanFanInputParamBO
from app.models.bo.hanfan.hanfan_reason_status_bo import HanFanReasonStatusBO
from app.models.bo.hanfan.hanfan_model_input_bo import HanFanModelInputBO
from app.models.po.hanfan.hanfan_model_input_po import HanFanModelInputPO
from app.models.po.hanfan.hanfan_new_predict_po import HanfanNewPredictPO
from app.models.po.hanfan.hanfan_predict_po import HanFanPredictPO
from app.models.bo.gaolu.gaolu_reason_input_bo import GaoLuReasonInputBO
from typing import List, Dict, Optional

from app.services.dal import hanfan_dao_service
from app.services.dal.hanfan_dao_service import hanfan_history_between, get_hanfan_result_one, \
    get_latest_input_cache, predict_result_insert, hanfan_history_between_json, cal_hanfan_predict_column \
    , get_input_cache_by_datetime, cal_hanfan_yuanranliao_ratio, delete_from_to_predict, add_backtracking_data_list
from app.services.models.hanfan_score_model import hanfan_score_model
from app.services.models.gaolu_reason_model import gaolu_reason_model
from app.services.models import const
from app.utils import cal_util
from app.utils.constant import HanFanStatus
from app.utils.sys_utils import get_list_intersect, copy_properties, get_time_round_and_adjust
import collections
from app.services.models.const import NORMAL_CODE
import datetime
from app.exts import ironman_redis, data_container
from flask import current_app
import pandas as pd
import json
import logging as log
from app.services.models.hanfan_dict import hanfan_oracle_dict


def get_predict_data(start, end) -> list:
    records = convert.query(HanfanNewPredictPO,
                            HanfanNewPredictPO.DATE_TIME >= start,
                            HanfanNewPredictPO.DATE_TIME <= end).all()
    return records


def prediction_data(query_time):
    record: HanFanPredictPO = get_hanfan_result_one(query_time)
    ret_dict = {}
    if record is not None:
        needed_status_list = get_list_intersect(record.__dir__(), HanFanReasonStatusBO.exposed_param_list())
        status_dict = collections.OrderedDict()
        normal_status_dict = {}
        abnormal_status_dict = {}
        for param_name in needed_status_list:
            status = record.__getattribute__(param_name)
            if status != NORMAL_CODE:
                abnormal_status_dict[param_name] = status
            else:
                normal_status_dict[param_name] = NORMAL_CODE

        status_dict.update(abnormal_status_dict, **normal_status_dict)
        needed_value_list = get_list_intersect(record.__dir__(), HanFanInputParamBO.exposed_param_list())
        value_dict = {}
        for param_name in needed_value_list:
            value_dict[param_name] = round(
                record.__getattribute__(param_name), 2) if record.__getattribute__(
                param_name) is not None else None

        ret_dict = {'curScore': record.CURRENT_HF,
                    'predictScore': record.FUTURE_HF_4H,
                    'bestScore': record.BEST_HF,
                    'DateTime': record.DateTime.strftime("%Y-%m-%d %H:%M:%S"),
                    'value': value_dict,
                    'status': status_dict,
                    'statusDict': HanFanReasonStatusBO.exposed_param_dict(),
                    'valueDict': HanFanInputParamBO.exposed_param_dict()}

        predict_record: HanfanNewPredictPO = convert.query(HanfanNewPredictPO,
                                                           order_by=HanfanNewPredictPO.id.desc()).first()
        ret_dict['shoude'] = predict_record.CG_LT_GL_GL04_Vshoude

        return ret_dict
    return ret_dict


def fuel_tracking(query_time, params=[]):
    record = get_hanfan_result_one(query_time)
    ret_dict = {}
    if record is not None:
        # TODO fuel processing
        ore_fuel_param_list = get_list_intersect(record.__dir__(), HanFanFuelTrackingBO.exposed_ore_fuel_param_list())
        coke_fuel_param_list = get_list_intersect(record.__dir__(), HanFanFuelTrackingBO.expose_coke_fuel_param_list())
        custom_param_list = []
        if params is not None:
            custom_param_list = get_list_intersect(record.__dir__(), params)
        ore_fuel_dict = {}
        coke_fuel_dict = {}
        custom_param_dict = {}
        ore_fuel_mapping = HanFanFuelTrackingBO.exposed_ore_fuel_param_dict()
        coke_fuel_mapping = HanFanFuelTrackingBO.exposed_coke_fuel_param_dict()
        for param_name in ore_fuel_param_list:
            # 若值为0 则忽略
            if record.__getattribute__(param_name) > 0:
                ore_fuel_dict[ore_fuel_mapping[param_name]] = record.__getattribute__(param_name)
        for param_name in coke_fuel_param_list:
            # 若值为0 则忽略
            if record.__getattribute__(param_name) > 0:
                coke_fuel_dict[coke_fuel_mapping[param_name]] = record.__getattribute__(param_name)
        for param_name in custom_param_list:
            custom_param_dict[param_name] = record.__getattribute__(param_name)
        ret_dict = {
            'oreFuel': ore_fuel_dict,
            'cokeFuel': coke_fuel_dict,
            'customParams': custom_param_dict,
        }
    return ret_dict


def get_content_change_data(start, end, left='close', right='close', order_by=None):
    his_ret = get_hanfan_history_between(start=start, end=end, left=left, right=right, order_by=order_by)
    # start = get_time_round_and_adjust(start, step=-4, round_level='hour')
    # his_ret_before_4h = get_hanfan_history_between(start=start, end=end, left=left, right=right, order_by=order_by)

    start = get_time_round_and_adjust(start, step=-1, round_level='hour')
    his_ret_before_4h = get_hanfan_history_between(start=start, end=end, left=left, right=right, order_by=order_by)

    predict_data_list = []
    current_data_list = []
    datetime_list = []
    for po in his_ret:
        current_data_list.append(po.CURRENT_HF)
    for po in his_ret_before_4h:
        # date_time = po.GMT_CREATE + datetime.timedelta(hours=4)
        date_time = po.GMT_CREATE + datetime.timedelta(hours=1)
        datetime_list.append(date_time.strftime("%Y-%m-%d %H:%M:%S"))
        predict_data_list.append(po.FUTURE_HF_4H)
    content_change_dict = {
        'predictScore': predict_data_list,
        'currentScore': current_data_list,
        'date': datetime_list,
    }

    return content_change_dict


def get_hanfan_history_between(start, end, left='close', right='close', order_by=None) \
        -> List[HanFanPredictPO]:
    return hanfan_history_between(start, end, left, right, order_by=order_by)


def get_hanfan_fisrt_result(start, end, left='close', right='close', order_by=None) \
        -> Optional[HanFanPredictPO]:
    list: List[HanFanPredictPO] = hanfan_history_between(start, end, left, right, order_by=order_by)
    if len(list) > 0:
        return list[0]
    return None


def model_predict_online():
    """
    :return:
    """
    hanfan_model_input_po = get_latest_input_cache()
    CG_LT_GL_GL04_LSJY = None
    CG_LT_GL_GL04_DW = None
    CG_LT_GL_GL04_ZXQL = None  # T阀座温度/T顶温
    CG_LT_GL_GL04_XBYC = None
    CG_LT_GL_GL04_SBYC = None
    CG_LT_GL_GL04_YC = None
    CG_LT_GL_GL04_XBYCZB = None
    CG_LT_GL_GL04_ZBYCZB = None
    CG_LT_GL_GL04_SBYCZB = None
    CG_LT_GL_GL04_MQLYL = None

    D01 = hanfan_model_input_po.CG_LT_GL_GL04_LDWD01
    D02 = hanfan_model_input_po.CG_LT_GL_GL04_LDWD02
    D03 = hanfan_model_input_po.CG_LT_GL_GL04_LDWD03
    D04 = hanfan_model_input_po.CG_LT_GL_GL04_LDWD04
    FZWD = hanfan_model_input_po.CG_LT_GL_GL04_FZWD
    XBYC01 = hanfan_model_input_po.CG_LT_GL_GL04_XBYC01
    XBYC02 = hanfan_model_input_po.CG_LT_GL_GL04_XBYC01
    XBYC03 = hanfan_model_input_po.CG_LT_GL_GL04_XBYC01
    XBYC04 = hanfan_model_input_po.CG_LT_GL_GL04_XBYC01
    SBYC01 = hanfan_model_input_po.CG_LT_GL_GL04_SBYC01
    SBYC02 = hanfan_model_input_po.CG_LT_GL_GL04_SBYC02
    SBYC03 = hanfan_model_input_po.CG_LT_GL_GL04_SBYC03
    SBYC04 = hanfan_model_input_po.CG_LT_GL_GL04_SBYC04
    RFYL02 = hanfan_model_input_po.CG_LT_GL_GL04_RFYL02
    LDYL = hanfan_model_input_po.CG_LT_GL_GL04_LDYL
    COZXFX = hanfan_model_input_po.CG_LT_GL_GL04_COZXFX
    CO2ZXFX = hanfan_model_input_po.CG_LT_GL_GL04_CO2ZXFX

    LSJYPT1101 = hanfan_model_input_po.CG_LT_GL_GL04_LSJYPT1101
    LSJYPT1103 = hanfan_model_input_po.CG_LT_GL_GL04_LSJYPT1103
    LSJYPT1104 = hanfan_model_input_po.CG_LT_GL_GL04_LSJYPT1104
    LSJYPT1105 = hanfan_model_input_po.CG_LT_GL_GL04_LSJYPT1105
    LSJYPT1106 = hanfan_model_input_po.CG_LT_GL_GL04_LSJYPT1106
    LSJYPT1107 = hanfan_model_input_po.CG_LT_GL_GL04_LSJYPT1107
    LSJYPT1108 = hanfan_model_input_po.CG_LT_GL_GL04_LSJYPT1108

    if LSJYPT1101 and LSJYPT1103 and LSJYPT1104 and LSJYPT1105 and LSJYPT1106 and LSJYPT1107 and LSJYPT1108:
        CG_LT_GL_GL04_LSJY = (
                                     LSJYPT1101 + LSJYPT1103 + LSJYPT1104 + LSJYPT1105 + LSJYPT1106 + LSJYPT1107 + LSJYPT1108) / 7

    if D01 and D02 and D03 and D04:
        CG_LT_GL_GL04_DW = 0.25 * (D01 + D02 + D03 + D04)

    if CG_LT_GL_GL04_DW and FZWD:
        CG_LT_GL_GL04_ZXQL = float(FZWD / CG_LT_GL_GL04_DW)

    if XBYC01 and XBYC02 and XBYC03 and XBYC04:
        CG_LT_GL_GL04_XBYC = 0.25 * (XBYC01 + XBYC02 + XBYC03 + XBYC04)

    if SBYC01 and SBYC02 and SBYC03 and SBYC04:
        CG_LT_GL_GL04_SBYC = 0.25 * (SBYC01 + SBYC02 + SBYC03 + SBYC04)

    if RFYL02 and LDYL:
        CG_LT_GL_GL04_YC = float(RFYL02 - LDYL)

    if CG_LT_GL_GL04_XBYC and CG_LT_GL_GL04_YC:
        CG_LT_GL_GL04_XBYCZB = float(CG_LT_GL_GL04_XBYC / CG_LT_GL_GL04_YC)

    if CG_LT_GL_GL04_XBYC and CG_LT_GL_GL04_SBYC:
        CG_LT_GL_GL04_ZBYCZB = 1 - CG_LT_GL_GL04_XBYC - CG_LT_GL_GL04_SBYC

    if CG_LT_GL_GL04_SBYC and CG_LT_GL_GL04_YC:
        CG_LT_GL_GL04_SBYCZB = float(CG_LT_GL_GL04_SBYC / CG_LT_GL_GL04_YC)

    if COZXFX and CO2ZXFX:
        CG_LT_GL_GL04_MQLYL = float(CO2ZXFX / (COZXFX + CO2ZXFX))

    hanfan_model_input_po.CG_LT_GL_GL04_LSJY = CG_LT_GL_GL04_LSJY
    hanfan_model_input_po.CG_LT_GL_GL04_DW = CG_LT_GL_GL04_DW
    hanfan_model_input_po.CG_LT_GL_GL04_ZXQL = CG_LT_GL_GL04_ZXQL
    hanfan_model_input_po.CG_LT_GL_GL04_XBYC = CG_LT_GL_GL04_XBYC
    hanfan_model_input_po.CG_LT_GL_GL04_SBYC = CG_LT_GL_GL04_SBYC
    hanfan_model_input_po.CG_LT_GL_GL04_YC = CG_LT_GL_GL04_YC
    hanfan_model_input_po.CG_LT_GL_GL04_XBYCZB = CG_LT_GL_GL04_XBYCZB
    hanfan_model_input_po.CG_LT_GL_GL04_ZBYCZB = CG_LT_GL_GL04_ZBYCZB
    hanfan_model_input_po.CG_LT_GL_GL04_SBYCZB = CG_LT_GL_GL04_SBYCZB
    hanfan_model_input_po.CG_LT_GL_GL04_MQLYL = CG_LT_GL_GL04_MQLYL

    hanfan_model_input_po = cal_hanfan_yuanranliao_ratio(hanfan_model_input_po)
    hanfan_model_input_po = cal_hanfan_predict_column(hanfan_model_input_po)

    hanfan_model_input_bo = HanFanModelInputBO()
    gaolu_reason_input_bo = GaoLuReasonInputBO()
    if hanfan_model_input_po is None:
        return None

    copy_properties(hanfan_model_input_po, hanfan_model_input_bo)
    score = get_hanfan_score(hanfan_model_input_bo)

    # 状态处理逻辑与高炉相同
    copy_properties(hanfan_model_input_po, gaolu_reason_input_bo)
    # gaolu_reason_status_bo = get_gaolu_reason(gaolu_reason_input_bo)

    hanfan_predict_po = HanFanPredictPO()
    # predict value
    hanfan_predict_po.FUTURE_HF_4H = float(score)
    # current value
    hanfan_predict_po.CURRENT_HF = hanfan_model_input_po.CG_LT_GL_GL04_Tie_V

    # best value
    hanfan_predict_po.BEST_HF = hanfan_best_score(hanfan_model_input_po.CG_LT_GL_GL04_Yuanranliao_Ore_V2O5)
    copy_properties(hanfan_model_input_po, hanfan_predict_po)
    # copy_properties(gaolu_reason_status_bo, hanfan_predict_po)

    date = None
    if hanfan_model_input_po.FDate is None:
        hanfan_predict_po.DateTime = None
    elif isinstance(hanfan_model_input_po.FDate, str):
        date = datetime.datetime.strptime(hanfan_model_input_po.FDate, "%Y-%m-%d")
        hanfan_predict_po.DateTime = date + datetime.timedelta(hours=hanfan_model_input_po.FHour)
    else:
        date = hanfan_model_input_po.FDate
        hanfan_predict_po.DateTime = date + datetime.timedelta(hours=hanfan_model_input_po.FHour)

    # insert record
    predict_result_insert(hanfan_predict_po)

    hanfan_dict: Dict[str, any] = ironman_redis.hget_all_str_decode("hanfan")
    hanfan_non_oracle_data = [k for k, v in hanfan_dict.items() if k not in hanfan_oracle_dict]
    ironman_redis.hdel("hanfan", hanfan_non_oracle_data)
    # ironman_redis.hmset("hanfan",hanfan_oracle_data)
    # data backtracking
    backtracking_data(hanfan_predict_po.GMT_CREATE)


def model_predict_by_data_backtracking(query_time, cache_key):
    """
    用于数据回溯时的预测
    :return:
    """
    hanfan_model_input_po: HanFanModelInputPO = get_input_cache_by_datetime(query_time, cache_key)
    CG_LT_GL_GL04_LSJY = None
    CG_LT_GL_GL04_DW = None
    CG_LT_GL_GL04_ZXQL = None  # T阀座温度/T顶温
    CG_LT_GL_GL04_XBYC = None
    CG_LT_GL_GL04_SBYC = None
    CG_LT_GL_GL04_YC = None
    CG_LT_GL_GL04_XBYCZB = None
    CG_LT_GL_GL04_ZBYCZB = None
    CG_LT_GL_GL04_SBYCZB = None
    CG_LT_GL_GL04_MQLYL = None

    D01 = hanfan_model_input_po.CG_LT_GL_GL04_LDWD01
    D02 = hanfan_model_input_po.CG_LT_GL_GL04_LDWD02
    D03 = hanfan_model_input_po.CG_LT_GL_GL04_LDWD03
    D04 = hanfan_model_input_po.CG_LT_GL_GL04_LDWD04
    FZWD = hanfan_model_input_po.CG_LT_GL_GL04_FZWD
    XBYC01 = hanfan_model_input_po.CG_LT_GL_GL04_XBYC01
    XBYC02 = hanfan_model_input_po.CG_LT_GL_GL04_XBYC01
    XBYC03 = hanfan_model_input_po.CG_LT_GL_GL04_XBYC01
    XBYC04 = hanfan_model_input_po.CG_LT_GL_GL04_XBYC01
    SBYC01 = hanfan_model_input_po.CG_LT_GL_GL04_SBYC01
    SBYC02 = hanfan_model_input_po.CG_LT_GL_GL04_SBYC02
    SBYC03 = hanfan_model_input_po.CG_LT_GL_GL04_SBYC03
    SBYC04 = hanfan_model_input_po.CG_LT_GL_GL04_SBYC04
    RFYL02 = hanfan_model_input_po.CG_LT_GL_GL04_RFYL02
    LDYL = hanfan_model_input_po.CG_LT_GL_GL04_LDYL
    COZXFX = hanfan_model_input_po.CG_LT_GL_GL04_COZXFX
    CO2ZXFX = hanfan_model_input_po.CG_LT_GL_GL04_CO2ZXFX

    LSJYPT1101 = hanfan_model_input_po.CG_LT_GL_GL04_LSJYPT1101
    LSJYPT1103 = hanfan_model_input_po.CG_LT_GL_GL04_LSJYPT1103
    LSJYPT1104 = hanfan_model_input_po.CG_LT_GL_GL04_LSJYPT1104
    LSJYPT1105 = hanfan_model_input_po.CG_LT_GL_GL04_LSJYPT1105
    LSJYPT1106 = hanfan_model_input_po.CG_LT_GL_GL04_LSJYPT1106
    LSJYPT1107 = hanfan_model_input_po.CG_LT_GL_GL04_LSJYPT1107
    LSJYPT1108 = hanfan_model_input_po.CG_LT_GL_GL04_LSJYPT1108

    if LSJYPT1101 and LSJYPT1103 and LSJYPT1104 and LSJYPT1105 and LSJYPT1106 and LSJYPT1107 and LSJYPT1108:
        CG_LT_GL_GL04_LSJY = (
                                     LSJYPT1101 + LSJYPT1103 + LSJYPT1104 + LSJYPT1105 + LSJYPT1106 + LSJYPT1107 + LSJYPT1108) / 7

    if D01 and D02 and D03 and D04:
        CG_LT_GL_GL04_DW = 0.25 * (D01 + D02 + D03 + D04)

    if CG_LT_GL_GL04_DW and FZWD:
        CG_LT_GL_GL04_ZXQL = float(FZWD / CG_LT_GL_GL04_DW)

    if XBYC01 and XBYC02 and XBYC03 and XBYC04:
        CG_LT_GL_GL04_XBYC = 0.25 * (XBYC01 + XBYC02 + XBYC03 + XBYC04)

    if SBYC01 and SBYC02 and SBYC03 and SBYC04:
        CG_LT_GL_GL04_SBYC = 0.25 * (SBYC01 + SBYC02 + SBYC03 + SBYC04)

    if RFYL02 and LDYL:
        CG_LT_GL_GL04_YC = float(RFYL02 - LDYL)

    if CG_LT_GL_GL04_XBYC and CG_LT_GL_GL04_YC:
        CG_LT_GL_GL04_XBYCZB = float(CG_LT_GL_GL04_XBYC / CG_LT_GL_GL04_YC)

    if CG_LT_GL_GL04_XBYC and CG_LT_GL_GL04_SBYC:
        CG_LT_GL_GL04_ZBYCZB = 1 - CG_LT_GL_GL04_XBYC - CG_LT_GL_GL04_SBYC

    if CG_LT_GL_GL04_SBYC and CG_LT_GL_GL04_YC:
        CG_LT_GL_GL04_SBYCZB = float(CG_LT_GL_GL04_SBYC / CG_LT_GL_GL04_YC)

    if COZXFX and CO2ZXFX:
        CG_LT_GL_GL04_MQLYL = float(CO2ZXFX / (COZXFX + CO2ZXFX))

    hanfan_model_input_po.CG_LT_GL_GL04_LSJY = CG_LT_GL_GL04_LSJY
    hanfan_model_input_po.CG_LT_GL_GL04_DW = CG_LT_GL_GL04_DW
    hanfan_model_input_po.CG_LT_GL_GL04_ZXQL = CG_LT_GL_GL04_ZXQL
    hanfan_model_input_po.CG_LT_GL_GL04_XBYC = CG_LT_GL_GL04_XBYC
    hanfan_model_input_po.CG_LT_GL_GL04_SBYC = CG_LT_GL_GL04_SBYC
    hanfan_model_input_po.CG_LT_GL_GL04_YC = CG_LT_GL_GL04_YC
    hanfan_model_input_po.CG_LT_GL_GL04_XBYCZB = CG_LT_GL_GL04_XBYCZB
    hanfan_model_input_po.CG_LT_GL_GL04_ZBYCZB = CG_LT_GL_GL04_ZBYCZB
    hanfan_model_input_po.CG_LT_GL_GL04_SBYCZB = CG_LT_GL_GL04_SBYCZB
    hanfan_model_input_po.CG_LT_GL_GL04_MQLYL = CG_LT_GL_GL04_MQLYL

    hanfan_model_input_po = cal_hanfan_yuanranliao_ratio(hanfan_model_input_po)
    hanfan_model_input_po = cal_hanfan_predict_column(hanfan_model_input_po)

    hanfan_model_input_bo = HanFanModelInputBO()
    gaolu_reason_input_bo = GaoLuReasonInputBO()
    if hanfan_model_input_po is None:
        return None

    copy_properties(hanfan_model_input_po, hanfan_model_input_bo)
    score = get_hanfan_score(hanfan_model_input_bo)

    # 状态处理逻辑与高炉相同
    copy_properties(hanfan_model_input_po, gaolu_reason_input_bo)
    gaolu_reason_status_bo = get_gaolu_reason(gaolu_reason_input_bo)

    hanfan_predict_po = HanFanPredictPO()
    # predict value
    hanfan_predict_po.FUTURE_HF_4H = float(score)
    # current value
    hanfan_predict_po.CURRENT_HF = hanfan_model_input_po.CG_LT_GL_GL04_Tie_V

    # best value
    hanfan_predict_po.BEST_HF = hanfan_best_score(hanfan_model_input_po.CG_LT_GL_GL04_Yuanranliao_Ore_V2O5)
    copy_properties(hanfan_model_input_po, hanfan_predict_po)
    copy_properties(gaolu_reason_status_bo, hanfan_predict_po)

    date = None
    if hanfan_model_input_po.FDate is None:
        hanfan_predict_po.DateTime = None
    elif isinstance(hanfan_model_input_po.FDate, str):
        date = datetime.datetime.strptime(hanfan_model_input_po.FDate, "%Y-%m-%d")
        hanfan_predict_po.DateTime = date + datetime.timedelta(hours=hanfan_model_input_po.FHour)
    else:
        date = hanfan_model_input_po.FDate
        hanfan_predict_po.DateTime = date + datetime.timedelta(hours=hanfan_model_input_po.FHour)

    return hanfan_predict_po


def get_hanfan_score(hanfan_model_input_bo):
    return hanfan_score_model.simple_process(hanfan_model_input_bo)


def get_gaolu_reason(gaolu_reason_input_bo):
    return gaolu_reason_model.process(gaolu_reason_input_bo)


def param_dist_dict(start, end, refresh=False):
    """
    :param start:
    :param end:
    :param refresh: 是否刷新 data_container里面的数据
    :return:
    """
    # if refresh == 'true':
    #     reload_data_container(key='hanfan_param_distribution', bin_num=None, start=start, end=end)

    try:
        if start is None and end is None:
            param_dist_dict_json = data_container['hanfan_param_distribution']
        else:
            start_str = datetime.datetime.strftime(start, "%Y-%m-%d")
            end_str = datetime.datetime.strftime(end, "%Y-%m-%d")
            param_dist_dict_json = ironman_redis.load("hanfan_param_dist_dic_" + start_str + "_" + end_str)

            if param_dist_dict_json is None:
                param_dist_dict_json = reload_data_container(key='hanfan_param_distribution', bin_num=None, start=start, end=end)
                # param_dist_dict_json = ironman_redis.load("hanfan_param_dist_dic_" + start_str + "_" + end_str)
        return param_dist_dict_json
    except Exception as e:
        current_app.logger.info(e)


def param_quantile_dict(start, end, refresh=False):
    """
    :param start:
    :param end:
    :param refresh: 是否刷新 data_container里面的数据
    :return:
    """
    if refresh:
        reload_data_container(key='hanfan_param_quantile', start=start, end=end)

    try:
        param_quantile_dict_json = json.dumps(data_container['hanfan_param_quantile'])
        return param_quantile_dict_json
    except Exception as e:
        current_app.logger.info(e)


def reload_data_container(key, bin_num, start=None, end=None):
    if bin_num is None:
        bin_num = current_app.config['HANFAN_PARAM_HISTORY_BINS']

    if 'hanfan_param_distribution' == key:
        history = hanfan_history_between_json(start, end)
        if history is None: return
        history_df = pd.read_json(history)
        dist_dict = hanfan_calculate_dist(start=None,
                                          end=None,
                                          df=history_df,
                                          bin_num=bin_num)

        start_str = datetime.datetime.strftime(start, "%Y-%m-%d")
        end_str = datetime.datetime.strftime(end, "%Y-%m-%d")
        key = "hanfan_param_dist_dic_" + start_str + "_" + end_str
        ironman_redis.dump(key, dist_dict)

        data_container['hanfan_param_distribution'] = dist_dict

        return dist_dict

    if 'hanfan_param_quantile' == key:
        history = hanfan_history_between_json(start, end)
        if history is None: return
        history_df = pd.read_json(history)
        quantile_dict = hanfan_calculate_quantile(start=start,
                                                  end=end,
                                                  df=history_df)
        data_container['hanfan_param_quantile'] = quantile_dict
        return quantile_dict


def hanfan_calculate_dist(start, end, df, bin_num):
    df['DateTime'] = pd.to_datetime(df['DateTime']).apply(lambda x: x.replace(tzinfo=None))  # 去掉时区
    if start and end:
        df = df[(start < df['DateTime']) & (df['DateTime'] < end)]
    param_list = HanFanInputParamBO.exposed_param_list()
    df = df[param_list]
    return calculate_dist(df, bin_num)


def calculate_dist(df, bin_num):
    """
    生成参数分布
    :param df:
    :param bin_num:
    :return:
    """
    dist_dict_outer = {}
    for col in df.columns:
        log.info("cut columns is " + col)
        param = pd.cut(df[col], bins=bin_num, retbins=True, include_lowest=True)
        param_norm = param[0].value_counts(sort=False, normalize=True).mul(100).array
        param_bins = param[1]
        bin_median_list = []
        for i in range(bin_num):
            # 保留两位小数
            bin_median_list.append(round(((param_bins[i] + param_bins[i + 1]) / 2), 2))
        dist_dict_inner = dict(zip(bin_median_list, param_norm))
        dist_dict_outer[col] = dist_dict_inner
    return dist_dict_outer


def hanfan_calculate_quantile(start, end, df):
    """
    生成参数percentile 结果
    :param start:
    :param end:
    :param df:
    :return:
    """
    df['DateTime'] = pd.to_datetime(df['DateTime']).apply(lambda x: x.replace(tzinfo=None))  # 去掉时区
    df = df[(start < df['DateTime']) & (df['DateTime'] < end)]
    # df = df.loc[:, ~(df.columns.str.contains('status$', case=False) | df.columns.str.contains('DateTime', case=False))]
    param_list = HanFanInputParamBO.exposed_param_list()
    df = df[param_list]
    return calculate_quantile(df)


def calculate_quantile(df):
    df_quantile = pd.DataFrame()
    for i in range(1, 101):
        df_quantile = df_quantile.append(df.quantile(i / 100))
    return df_quantile.to_dict()


def auto_score(last, current):
    cur_record: HanfanNewPredictPO = hanfan_dao_service.get_new_hanfan_result_one(current)
    ret_dict = {}
    if cur_record is not None:
        score_dict = get_auto_score_by_record(cur_record)
        ret_dict.update(score_dict)
        # 保存最新记录的时间点
    last_record = hanfan_dao_service.get_new_hanfan_result_one(last)
    if last_record is not None:
        last_score_dict = {'CG_LT_GL_GL04_Score': last_record.CG_LT_GL_GL04_Tie_V,
                           'CG_LT_GL_GL04_Status': "正常",
                           'DateTime': last_record.DATE_TIME.strftime("%Y-%m-%d %H:%M:%S")}
        ret_dict['lastHourScore'] = last_score_dict
    return ret_dict


from app.services.models.hanfan_reason_model import hanfan_reason_model


def get_auto_score_by_record(record: HanfanNewPredictPO):
    needed_status_list = get_list_intersect(record.__dir__(), HanFanReasonStatusBO.exposed_param_list())
    status_dict = collections.OrderedDict()
    value_dict = collections.OrderedDict()

    """
    分数大于85， 全部设为正常
    TODO：该逻辑从算法角度应该修改
    前端需求， 异常值放在前面
    """

    adjust = []
    name_dict = HanFanReasonStatusBO.exposed_param_dict()
    for param_name in needed_status_list:
        value = record.__getattribute__(param_name)
        status = hanfan_reason_model.get_param_status(record.CG_LT_GL_GL04_Yuanranliao_Ore_V2O5, param_name, value)
        scope = hanfan_reason_model.get_param_scope(record.CG_LT_GL_GL04_Yuanranliao_Ore_V2O5, param_name)

        # todo 临时处理
        if param_name == 'CG_LT_GL_GL04_FCoalRate':
            param_name = 'CG_LT_GL_GL04_FCokeRate'
        elif param_name == 'CG_LT_GL_GL04_FCokeRate':
            param_name = 'CG_LT_GL_GL04_FCoalRate'
        item = dict(key=param_name, desc=name_dict[param_name], status=status, scope=scope, value=value)
        adjust.append(item)

    cur_score_dict = {'CG_LT_GL_GL04_Score': record.CG_LT_GL_GL04_Tie_V,
                      'CG_LT_GL_GL04_Score_predict': record.CG_LT_GL_GL04_Tie_V_PREDICT,
                      'CG_LT_GL_GL04_Status': '正常',  # todo
                      'DateTime': record.DATE_TIME.strftime("%Y-%m-%d %H:%M:%S")}

    best_value = hanfan_reason_model.get_best_value(record.CG_LT_GL_GL04_Yuanranliao_Ore_V2O5)

    keywords = [
        dict(key="CG_LT_GL_GL04_Ftswd", desc="铁水温度", related="铁水温度", min=1465, max=1480),
        dict(key="CG_LT_GL_GL04_FCoalRate", desc="煤比", related="煤比", min=130, max=150),
        # dict(key="CG_LT_GL_GL04_Zha_Mg_Al", desc="焦炭40mm粒度", related="焦炭40mm粒度", min=57, max=58),
        dict(key="CG_LT_GL_GL04_Coke_Greater40mm", desc="焦炭40mm粒度", related="焦炭40mm粒度", min=57, max=58),
        dict(key="CG_LT_GL_GL04_RLB", desc="燃料比", related="燃料比", min=520, max=540),
        dict(key="CG_LT_GL_GL04_FYL02", desc="富氧率", related="富氧率", min=2.5, max=3),
        dict(key="CG_LT_GL_GL04_LLRSWD", desc="理论燃烧温度", related="理论燃烧温度", min=2340, max=2390),
        dict(key="CG_LT_GL_GL04_XFZDWPJ", desc="阀座_顶温", related="阀座_顶温", min=0.53, max=0.58),
    ]

    recommend_list = []
    for keyword in keywords:

        key = keyword['key']
        desc = keyword['desc']
        related = keyword['related']
        min = keyword['min']
        max = keyword['max']
        fact = record.__dict__.get(key)

        if fact < min:
            recommend = "{}偏低,建议将{}提高{}".format(desc, related, cal_util.round(min - fact,2))
            status = "低"
        elif fact > max:
            recommend = "{}偏高,建议将{}降低{}".format(desc, related, cal_util.round(fact - max,2))
            status = "高"
        else:
            recommend = "{}正常,建议保持此值".format(desc)
            status = "正常"
        recommend_list.append(dict(key=key, desc=desc,status=status, recommend=recommend))

    ret_dict = {'curScore': cur_score_dict,
                'bestValue': best_value,
                'adjust': adjust,
                'nameDict': HanFanReasonStatusBO.exposed_param_dict(),
                'shoude': record.CG_LT_GL_GL04_Vshoude,
                'recommend': recommend_list
                }
    return ret_dict


def hanfan_best_score(y_ore_V2O5: float):
    """
    最佳值衍生方法
    :return:
    """
    if float('-inf') < y_ore_V2O5 <= 0.17:
        return 0.1540
    elif 0.17 < y_ore_V2O5 <= 0.18:
        return 0.1563
    elif 0.18 < y_ore_V2O5 <= 0.19:
        return 0.1623
    elif 0.19 < y_ore_V2O5 <= 0.20:
        return 0.1633
    elif 0.20 < y_ore_V2O5 <= 0.21:
        return 0.1710
    elif 0.21 < y_ore_V2O5 <= 0.22:
        return 0.1738
    elif 0.22 < y_ore_V2O5 <= 0.23:
        return 0.1778
    elif 0.23 < y_ore_V2O5 <= 0.24:
        return 0.1870
    elif 0.24 < y_ore_V2O5 <= 0.25:
        return 0.1933
    elif 0.25 < y_ore_V2O5 <= 0.26:
        return 0.2053
    elif 0.26 < y_ore_V2O5 <= 0.27:
        return 0.2160
    elif 0.27 < y_ore_V2O5 <= 0.28:
        return 0.2188
    elif 0.28 < y_ore_V2O5 <= 0.29:
        return 0.2308
    elif 0.29 < y_ore_V2O5 <= 0.30:
        return 0.2343
    elif 0.30 < y_ore_V2O5 <= 0.31:
        return 0.2386
    elif 0.31 < y_ore_V2O5 <= 0.32:
        return 0.2448
    elif 0.32 < y_ore_V2O5 <= 0.33:
        return 0.2470
    elif 0.33 < y_ore_V2O5 <= 0.34:
        return 0.2790
    elif 0.34 < y_ore_V2O5 <= 0.35:
        return 0.2680
    elif 0.35 < y_ore_V2O5 <= 0.36:
        return 0.2710
    elif 0.36 < y_ore_V2O5 <= 0.37:
        return 0.2739
    elif 0.37 < y_ore_V2O5 <= 0.38:
        return 0.2920
    elif 0.38 < y_ore_V2O5 <= 0.39:
        return 0.2923
    elif 0.39 < y_ore_V2O5 <= float('-inf'):
        return 0.2885


def backtracking_data(start):
    """
    根据日期回溯数据
    :return:
    """
    # 更新当前小时的含钒数据
    __update_current_backtracking_data(start)

    # backtracking data
    # backtracking_data_list = []
    # for hour_before_start in range(1, 9):
    #     datetime_before_start = start - datetime.timedelta(hours=hour_before_start)
    #     hour = datetime_before_start.hour
    #     # hanfan hkey in redis
    #     key = HanFanStatus.HANFAN_CACHE_KEY_PREFIX + str(hour)
    #     value_dict = ironman_redis.hget_all_str_decode(key)
    #     if len(value_dict) > 0:
    #         hanfan_dao_service.dump_hanfan_data(start, end=None, cache_key=key)
    #     else:
    #         # 如果为空，取上个小时的redis数据dump到当前时间的hkey中
    #         datetime_before_one_hour = datetime_before_start + datetime.timedelta(hours=1)
    #         one_hour_ago_key = HanFanStatus.HANFAN_CACHE_KEY_PREFIX + str(datetime_before_one_hour.hour)
    #         one_hour_ago_value_dict = ironman_redis.hget_all_str_decode(one_hour_ago_key)
    #         ironman_redis.hmset(key, one_hour_ago_value_dict)
    #     # re-predict the hanfan score
    #     hanfan_predict_po = model_predict_by_data_backtracking(datetime_before_start, cache_key=key)
    #     backtracking_data_list.append(hanfan_predict_po)
    #
    # # delete hanfan_predict_po between backtracking_start and backtracking_end
    # backtracking_end = start - datetime.timedelta(hours=1)
    # backtracking_start = start - datetime.timedelta(hours=8)
    # delete_from_to_predict(backtracking_start, backtracking_end)
    # # re-insert the backtracking data
    # add_backtracking_data_list(backtracking_data_list)
    # return backtracking_data_list


def __update_current_backtracking_data(start):
    """
    更新当前小时的含钒数据: 将redis中hanfan hkey的数据更新到当前小时的hkey中去
    :return:
    """
    key = HanFanStatus.HANFAN_CACHE_KEY_PREFIX + str(start.hour)
    value_dict = ironman_redis.hget_all_str_decode(HanFanStatus.HANFAN_DEFAULT_CACHE_KEY)
    ironman_redis.hmset(key, value_dict)

# def param_dist_dict(start, end ,refresh) -> dict:
#     try:
#         model_repo_po = get_model_by_name_version(MODEL_INFO.HANFAN_HIS_DIST_NAME, MODEL_INFO.MODEL_VALID_VERSION_NUM)
#         param_dist_dict = model_repo_po.model
#         return param_dist_dict
#     except Exception as e:
#         current_app.logger.info(e)
#
#
# def param_quantile_dict() -> dict:
#     try:
#         model_repo_po = get_model_by_name_version(MODEL_INFO.HANFAN_HIS_QUANTILE_NAME,
#                                                   MODEL_INFO.MODEL_VALID_VERSION_NUM)
#         param_quantile_dict = model_repo_po.model
#         return param_quantile_dict
#     except Exception as e:
#         current_app.logger.info(e)
